<?php
/**
 * This is class is aim to be used to created objects.
 * @author Pablo
 * @since 1.0
 */
abstract class BlgData implements
	Iterator, //Override foreach behaviour
	ArrayAccess //Override for array access
{
	/**
	 * The main attributes of an entity
	 * @author Pablo
 	 * @since 1.0
	 */
	protected $attributes= array();
	
	/**
	 * Initialize attributes
	 * @author Pablo
 	 * @since 1.0
	 */
	protected function initializeAttributes(){
		if(!is_array($this->attributes)){
			$this->attributes= array();
		}
	}
	
	/**
	 * Return an attribute
	 * @param string $name Name
	 * @author Pablo
 	 * @since 1.0 
	 */
	public function __get($name) {
		return $this->get($name);
	}
	
	/**
	 * Set an attribute or a piece of metadata
	 * 
	 * @param string $name Name
	 * @param mixed $value Value
	 * @author Pablo
 	 * @since 1.0
	 */
	public function __set($name, $value){
		$this->set($name, $value);
	}
	
	/**
	 * Test if property is set
	 * 
	 * @tip Use isset($entity->property)
	 * 
	 * @param string $name The name of the attribute or metadata
	 * @return boolean True if the data is not NULL, false in not.
	 * @author Pablo
 	 * @since 1.0
	 */
	public function __isset($name){
		return ($this->attributes[$name] !== NULL);
	}
	
	/**
	 * Unset an attribute
	 * 
	 * @param $name
	 * @author Pablo
 	 * @since 1.0 
	 */
	public function __unset($name){
		unset($this->attributes[$name]);
	}
	
	/**
	 * Fetch the specified attribute
	 * 
	 * @param string $name The attribute to fetch
	 * @return mixed The attribute, if it exists. Otherwise, null.
	 * @author Pablo
 	 * @since 1.0
	 */
	protected function get($name){
		if(array_key_exists($name, $this->attributes)){
			return $this->attributes[$name];
		}
		
		return NULL;
	}
	
	/**
	 * Set the specified attribute
	 * 
	 * @param string $name The attribute to set
	 * @param mixed $value The value to set it to
	 * @author Pablo
 	 * @since 1.0 
	 */
	protected function set($name, $value){
		if(array_key_exists($name, $this->attributes)){
			$this->attributes[$name]= $value;
		}
	}
	
	/**
	 * Get a URL for this object
	 * 
	 * @return string
	 * @author Pablo
 	 * @since 1.0
	 */
	abstract public function getURL();
	
	/**
	 * Save data
	 * 
	 * @return bool
	 * @author Pablo
 	 * @since 1.0
	 */
	abstract public function save();
	
	/**
	 * Delete data
	 * 
	 * @return bool
	 * @author Pablo
 	 * @since 1.0
	 */
	abstract public function delete();
		
	/**
	 * Return the class name of the object
	 * 
	 * @return string
	 * @author Pablo
 	 * @since 1.0
	 */
	public function getClassName(){
		return get_class($this);
	}	
	
	/***********************************************************
	 * 					  ITERATOR INTERFACE
	 ***********************************************************/
	
	//This lets an entity's attributes be displayed using foreach as a normal array

	private $valid= FALSE;
	
	/**
	 * Iterator interface::rewind()
	 * @see Iterator::rewind()
	 * @return void
	 * @author Pablo
 	 * @since 1.0
	 */	
	public function rewind(){
		$this->valid = (FALSE !== reset($this->attributes));
	}
	
	/**
	 * Iterator interface::current()
	 * @see Iterator::current()
	 * @return mixed
	 * @author Pablo
 	 * @since 1.0 
	 */
	public function current() {
		return current($this->attributes);
	}
	
	/**
	 * Iterator interface::key()
	 * @see Iterator::key()
	 * @return mixed
	 * @author Pablo
 	 * @since 1.0
	 */
	public function key() {
		return key($this->attributes);
	}
	
	/**
	 * Iterator interface::next()
	 * @see Iterator::next()
	 * @return void
	 * @author Pablo
 	 * @since 1.0
	 */	
	public function next(){
		$this->valid = (FALSE !== next($this->attributes));
	}
	
	/**
	 * Iterator interface::valid()
	 * @see Iterator::valid()
	 * @return bool
	 * @author Pablo
 	 * @since 1.0
	 */
	public function valid(){
		return $this->valid;
	}
	
	/***********************************************************
	 * 					ARRAY ACCESS INTERFACE
	 ***********************************************************/

	//This lets an entity's attributes be accessed like an associative array.
	
	/**
	 * ArrayAccess interface::offsetSet()
	 * @see ArrayAccess::offsetSet()
	 * 
	 * @param mixed $key
	 * @param mixed $value
	 * @author Pablo
 	 * @since 1.0
	 */
	public function offsetSet($key, $value){
		if(array_key_exists($key, $this->attributes)){
			$this->attributes[$key]= $value;
		}
	}

	/**
	 * ArrayAccess interface::offsetGet()
	 * @see ArrayAccess::offsetGet()
	 * 
	 * @param mixed $key
	 * @author Pablo
 	 * @since 1.0
	 */
	public function offsetGet($key){
		if(array_key_exists($key, $this->attributes)){
			return $this->attributes[$key];
		}		
	}	
	
	/**
	 * ArrayAccess interface::offsetUnset()
	 * @see ArrayAccess::offsetUnset()
	 * 
	 * @param mixed $key
	 * @author Pablo
 	 * @since 1.0
	 */	
	public function offsetUnset($key){
		if(array_key_exists($key, $this->attributes)){
			// Full unsetting is dangerous for our objects
			$this->attributes[$key] = "";
		}		
	}
	
	/**
	 * ArrayAccess interface::offsetExists()
	 * @see ArrayAccess::offsetExists()
	 * 
	 * @param mixed $offset
	 * @author Pablo
 	 * @since 1.0
	 */
	public function offsetExists($offset){
		return array_key_exists($offset, $this->attributes);
	}
	
}